#include <reg52.h>
#include <intrins.h>

typedef unsigned long u32_t;
typedef unsigned int u16_t; 
typedef unsigned char u8_t;

// XTAL = 11Mhz, times pre order = 90.91ns
// Per time = 90.91ns * 16 = 1.45454545us
// If wish start after 820us, n = 564
// hex(65535 - 564) = 0xFDCB

# define TH0_DEFAULT (0xFD)
# define TL0_DEFAULT (0x0F)

// u8_t *analog_list = {x, y, z}, means x.yz
// For example, {4, 1, 7} = 4.17
// Max measure is 9.99
u8_t analog_list[3] = {0, 0, 0};
u16_t adc_digit = 0;
u16_t cap_digit = 0;
u8_t start_timing_flag = 0;
u8_t meter_class = 0;

sbit test_port = P3^0;

enum METER_CLASS {
	NAN_METER, VOL_METER, CAP_METER
};

void init_interrupt_0() {
	IT0 = 1;		// Interrupt when INT0 find singal falling down
	EX0 = 1;		// Enable INT0
}

void init_interrupt_1() {
	TH0 = TH0_DEFAULT;
	TL0 = TL0_DEFAULT;

	TR0 = 1;
}

void init_interrupt_2() {
	IT1 = 1;
	EX1 = 1;
}

void init_interrupt_3() {
	TH1 = 0;
	TL1 = 0;
	
	TR1 = 1;
}

void init_timer() {
	TMOD = 0x11;	// MODE 1
	
	TF0 = 0;
	TF1 = 0;
	
	ET0 = 1;
	ET1 = 1;
}


void init() {
	init_timer();
	init_interrupt_0();
	init_interrupt_2();
	// Enable All Interrupt
	EA = 1;
}

u16_t get_ad_converter(void) {
	u16_t ans = 0x0000;
	u16_t d8 = (P2 & 0x01);			// D8 to P2.0
	u16_t d7_d0 = P0;						// D7 to D0 connect from P0.7 to P0.0
	
	ans = d8 << 8;
	ans += d7_d0;
	
	return ans;
}


u16_t calculate_vol(u16_t ad_digit) {
	u16_t tmp_ans;
	
	tmp_ans = ad_digit * 2 * 10;
	if (tmp_ans >= 210)					// Make sure (tmp_ans - 210 >= 0)
		tmp_ans -= 210;						// Don't ask me why, the ans always bigger over 0.2V
	tmp_ans += 5;
	tmp_ans /= 10;
	
	return tmp_ans;
}

u16_t get_capacitance_from_555_timer(void) {
	u32_t ans = 0x0000;
	ans = (TH1 << 8);
	ans += TL1;
	
	ans *= 131;
	ans /= 670;
	//ans *= 1571*5;
	//ans /= 6700*6;
	//ans *= 1728;
	//ans /= 7370;
	
	return (u16_t) (ans);
}

void set_analog_list(u8_t hundreds_place, u8_t tens_place, u8_t ones_place) {
	analog_list[0] = hundreds_place;
	analog_list[1] = tens_place;
	analog_list[2] = ones_place;
}


void conver_digit_to_analog(u16_t digit) {
	u8_t ones_place, tens_place, hundreds_place;
	
	if (digit > 999)
		digit = 999;
	
	ones_place = digit % 10;
	digit /= 10;
	tens_place = digit % 10;
	hundreds_place = digit / 10;
	
	set_analog_list(hundreds_place, tens_place, ones_place);
}

void show_num(void) {
	u8_t lower, upper;

	upper = (analog_list[0] << 4) + analog_list[1];
	lower = (analog_list[2] << 4);
	
	P1 = upper;				// Set P1 as upper
	P3 &= 0x0f;				// Set from P3.7 to P3.4 as 0
	P3 |= lower;			// Set from P3.7 to P3.4 as lower
}

// Because Miltisim runs slow, we use LED to show what step the MCU is
void show_now_state(u8_t hundreds_place, u8_t tens_place, u8_t ones_place) {
	set_analog_list(hundreds_place, tens_place, ones_place);
	show_num();
}

// When INT0 comes, start Timer 
void when_interrupt0() interrupt 0 {
	init_interrupt_1();
}

// When timer Interrupt, get adc_digit
void when_interrupt1() interrupt 1 {
	adc_digit = get_ad_converter();
	meter_class = VOL_METER;
}

void when_interrupt2() interrupt 2 {
	if (start_timing_flag) {
		TR1 = 0;
		test_port = 0;
		cap_digit = get_capacitance_from_555_timer();
		meter_class = CAP_METER;
		start_timing_flag = 0;
	} else {
		init_interrupt_3();
		test_port = 1;
		start_timing_flag = 1;
	}
}

void when_interrupt3() interrupt 3 {
	
}

void main() {
	u16_t adc_digit_cal;
	
	show_now_state(0x0b, 0x01, 0x0d);
	init();
	show_now_state(0x00, 0x00, 0x00);
	
	while(1) {
		switch (meter_class) {
			case VOL_METER:
				adc_digit_cal = calculate_vol(adc_digit);
				conver_digit_to_analog(adc_digit_cal);
				show_num();
				meter_class = NAN_METER;
				break;
			case CAP_METER:
				conver_digit_to_analog(cap_digit);
				show_num();
				meter_class = NAN_METER;
				break;
			default:
				meter_class = NAN_METER;
				break;
		}
	}
}
